﻿using System;
using System.Collections.Generic;
using Autodesk.Revit.DB;
using Autodesk.Revit.UI;
using YArchitech.Revit;
using YArchitech.Revit.RevitExtension;
using YJKExcelFormTool.DataDefine;
using YJKExcelFormTool.Utilities;

namespace YJKExcelFormTool.Analyser
{
	public class FamilyTableAnalyser
	{
		public TableHead TheTableHead
		{
			get
			{
				return this.m_HeadInfos;
			}
		}

		public FamilyTableAnalyser(ExternalCommandData commandData, Autodesk.Revit.DB.Document familyDocument)
		{
			this.m_Revit = commandData;
			this.m_FamilyDocument = familyDocument;
		}

		public bool Analyse(List<DetailLine> headLineList, List<TextElement> textNoteList, ref string message)
		{
			this.ClassifyLines(headLineList);
			if (!this.Validating(ref message))
			{
				return false;
			}
			this.GetHeadInfos();
			this.SplitLines();
			this.SearchCells(textNoteList);
			return true;
		}

		private void ClassifyLines(List<DetailLine> headLineList)
		{
			foreach (DetailLine detailLine in headLineList)
			{
				if ((detailLine.LineStyle as GraphicsStyle).GraphicsStyleCategory.Id.IntegerValue == -2000150)
				{
					Line line = detailLine.GeometryCurve as Line;
					if (!(null == line))
					{
						XYZ direction = line.Direction;
						XYZ hyendPoint = line.GetEndPoint(0);
						XYZ hyendPoint2 = line.GetEndPoint(1);
						if (direction.IsAlmostEqualTo(XYZ.BasisX))
						{
							this.m_HorizontalLineList.Add(YJKLineEx.YJKGetBound(hyendPoint, hyendPoint2));
						}
						else if (direction.IsAlmostEqualTo(-XYZ.BasisX))
						{
							this.m_HorizontalLineList.Add(YJKLineEx.YJKGetBound(hyendPoint2, hyendPoint));
						}
						else if (direction.IsAlmostEqualTo(XYZ.BasisY))
						{
							this.m_VerticalLineList.Add(YJKLineEx.YJKGetBound(hyendPoint, hyendPoint2));
						}
						else if (direction.IsAlmostEqualTo(-XYZ.BasisY))
						{
							this.m_VerticalLineList.Add(YJKLineEx.YJKGetBound(hyendPoint2, hyendPoint));
						}
					}
				}
			}
			this.MergeOverlapLines();
			this.m_HorizontalLineList.Sort(new ParallelLinesComparer(-XYZ.BasisY));
			this.m_VerticalLineList.Sort(new ParallelLinesComparer(XYZ.BasisX));
		}

		private bool Validating(ref string message)
		{
			if (this.m_HorizontalLineList.Count < 2 || this.m_VerticalLineList.Count < 2)
			{
				message = "table is invalidate";
				return false;
			}
			return true;
		}

		private void GetHeadInfos()
		{
			int num = 0;
			List<double> list = new List<double>();
			for (int i = 1; i < this.m_HorizontalLineList.Count; i++)
			{
				XYZ hyendPoint = this.m_HorizontalLineList[i - 1].GetEndPoint(0);
				double num2 = Geometry.CalculateFootPoint(this.m_HorizontalLineList[i], hyendPoint).DistanceTo(hyendPoint);
				if (!Geometry.IsEqual(num2, 0.0))
				{
					num++;
					list.Add(num2);
				}
			}
			int num3 = 0;
			List<double> list2 = new List<double>();
			for (int i = 1; i < this.m_VerticalLineList.Count; i++)
			{
				XYZ hyendPoint2 = this.m_VerticalLineList[i - 1].GetEndPoint(0);
				double num4 = Geometry.CalculateFootPoint(this.m_VerticalLineList[i], hyendPoint2).DistanceTo(hyendPoint2);
				if (!Geometry.IsEqual(num4, 0.0))
				{
					num3++;
					list2.Add(num4);
				}
			}
			this.m_TablePosition = this.m_VerticalLineList[0].GetEndPoint(1);
			int badyStartRowNumber = num + 1;
			int badyEndRowNumber = 36;
			TableSourceInfo tableSourceInfo = new TableSourceInfo(this.m_FamilyDocument.PathName, -1, badyStartRowNumber, badyEndRowNumber);
			this.m_HeadInfos = new TableHead(TableHead._Tag_HeadType.HT_FAMILY, tableSourceInfo, null, num, num3, list, list2);
		}

		private void MergeOverlapLines()
		{
			this.MergeOverlapLines(ref this.m_HorizontalLineList);
			this.MergeOverlapLines(ref this.m_VerticalLineList);
		}

		private void MergeOverlapLines(ref List<Line> lines)
		{
			for (int i = 0; i < lines.Count; i++)
			{
				bool flag = true;
				while (flag)
				{
					flag = false;
					for (int j = i + 1; j < lines.Count; j++)
					{
						Line curve = lines[i];
						Line curve2 = lines[j];
						XYZ hyendPoint = curve.GetEndPoint(0);
						XYZ hyendPoint2 = curve.GetEndPoint(1);
						XYZ hyendPoint3 = curve2.GetEndPoint(0);
						XYZ hyendPoint4 = curve2.GetEndPoint(1);
						XYZ startPoint = null;
						XYZ endPoint = null;
						if (this.MergeOfTwoLine(hyendPoint, hyendPoint2, hyendPoint3, hyendPoint4, ref startPoint, ref endPoint))
						{
							lines[i] = YJKLineEx.YJKGetBound(startPoint, endPoint);
							lines.RemoveAt(j);
							flag = true;
							j--;
						}
					}
				}
			}
		}

		private bool MergeOfTwoLine(XYZ ptS1, XYZ ptE1, XYZ ptS2, XYZ ptE2, ref XYZ ptS, ref XYZ ptE)
		{
			if ((ptS1.IsAlmostEqualTo(ptS2) && ptE1.IsAlmostEqualTo(ptE2)) || (ptS1.IsAlmostEqualTo(ptE2) && ptE1.IsAlmostEqualTo(ptS2)))
			{
				ptS = ptS1;
				ptE = ptE1;
				return true;
			}
			if (Geometry.Is_Point_OnSegment(ptS1, ptE1, ptS2) && Geometry.Is_Point_OnSegment(ptS1, ptE1, ptE2))
			{
				ptS = ptS1;
				ptE = ptE1;
				return true;
			}
			if (Geometry.Is_Point_OnSegment(ptS2, ptE2, ptS1) && Geometry.Is_Point_OnSegment(ptS2, ptE2, ptE1))
			{
				ptS = ptS2;
				ptE = ptE2;
				return true;
			}
			if (Geometry.Is_Point_OnSegment(ptS1, ptE1, ptS2))
			{
				if (Geometry.Is_Point_OnSegment(ptS2, ptE2, ptS1))
				{
					ptS = ptE2;
					ptE = ptE1;
					return true;
				}
				if (Geometry.Is_Point_OnSegment(ptS2, ptE2, ptE1))
				{
					ptS = ptE2;
					ptE = ptS1;
					return true;
				}
			}
			else if (Geometry.Is_Point_OnSegment(ptS1, ptE1, ptE2))
			{
				if (Geometry.Is_Point_OnSegment(ptS2, ptE2, ptS1))
				{
					ptS = ptS2;
					ptE = ptE1;
					return true;
				}
				if (Geometry.Is_Point_OnSegment(ptS2, ptE2, ptE1))
				{
					ptS = ptS2;
					ptE = ptS1;
					return true;
				}
			}
			return false;
		}

		private void SplitLines()
		{
			for (int i = 0; i < this.m_HorizontalLineList.Count; i++)
			{
				for (int j = 0; j < this.m_VerticalLineList.Count; j++)
				{
					Line line = this.m_HorizontalLineList[i];
					Line line2 = this.m_VerticalLineList[j];
					IntersectionResultArray intersectionResultArray;
                    if ((int)line.Intersect(line2, out intersectionResultArray) == 8)
					{
						XYZ xyzpoint = intersectionResultArray.get_Item(0).XYZPoint;
						if (!xyzpoint.IsAlmostEqualTo(line.GetEndPoint(0)) && !xyzpoint.IsAlmostEqualTo(line.GetEndPoint(1)))
						{
							this.m_HorizontalLineList[i] = YJKLineEx.YJKGetBound(line.GetEndPoint(0), xyzpoint);
							this.m_HorizontalLineList.Add(YJKLineEx.YJKGetBound(xyzpoint, line.GetEndPoint(1)));
						}
						if (!xyzpoint.IsAlmostEqualTo(line2.GetEndPoint(0)) && !xyzpoint.IsAlmostEqualTo(line2.GetEndPoint(1)))
						{
							this.m_VerticalLineList[j] = YJKLineEx.YJKGetBound(line2.GetEndPoint(0), xyzpoint);
							this.m_VerticalLineList.Add(YJKLineEx.YJKGetBound(xyzpoint, line2.GetEndPoint(1)));
						}
					}
				}
			}
		}

		private bool SearchCells(List<TextElement> textNoteList)
		{
			List<MapEdge> list = new List<MapEdge>();
			List<Line> list2 = new List<Line>();
			list2.AddRange(this.m_HorizontalLineList);
			list2.AddRange(this.m_VerticalLineList);
			int num = 0;
			foreach (Line curve in list2)
			{
				XYZ hyendPoint = curve.GetEndPoint(0);
				XYZ hyendPoint2 = curve.GetEndPoint(1);
				MapEdge item = MapEdge.NewEdge(new ElementId(num), hyendPoint, hyendPoint2, 0.0, 0.0);
				list.Add(item);
				num++;
			}
			List<TableHeadCell> list3 = new List<TableHeadCell>();
			foreach (List<Curve> list4 in new LoopSearcher(this.m_Revit, false).GetCellsEdgeLoops(list))
			{
				BoundingBoxUV boundingBoxUV = null;
				foreach (Curve curve2 in list4)
				{
					Line line = curve2 as Line;
					if (boundingBoxUV == null)
					{
						boundingBoxUV = Geometry.CalculateBoundingBox2D(line);
					}
					else
					{
						BoundingBoxUV box = Geometry.CalculateBoundingBox2D(line);
						boundingBoxUV = Geometry.BoundingBoxesMerge(boundingBoxUV, box);
					}
				}
				XYZ ptCellLeftTop = new XYZ(boundingBoxUV.Min.U, boundingBoxUV.Max.V, 0.0);
				XYZ ptCellRigthBottom = new XYZ(boundingBoxUV.Max.U, boundingBoxUV.Min.V, 0.0);
				List<int> rowIndex = new List<int>();
				List<int> colIndex = new List<int>();
				if (this.GetCellRowColIndexList(this.m_HeadInfos, ptCellLeftTop, ptCellRigthBottom, ref rowIndex, ref colIndex))
				{
					TableHeadCell item2 = new TableHeadCell(rowIndex, colIndex, "", new TableHeadCellKey(""), TableHeadCell.CellInfoType.CIT_Text);
					list3.Add(item2);
				}
			}
			this.m_HeadInfos.TableHeadInfos = list3;
			this.MappingCellAndTextNote(textNoteList);
			return true;
		}

		private void MappingCellAndTextNote(List<TextElement> textNoteList)
		{
			Autodesk.Revit.DB.View view = null;
			FilteredElementCollector filteredElementCollector = new FilteredElementCollector(this.m_FamilyDocument);
			filteredElementCollector.OfClass(typeof(Autodesk.Revit.DB.View));
			foreach (Element element in filteredElementCollector)
			{
				if (element != null)
				{
					Autodesk.Revit.DB.View view2 = (Autodesk.Revit.DB.View)element;
					if ((int)view2.ViewType == 6)
					{
						view = view2;
						break;
					}
				}
			}
			if (view == null)
			{
				return;
			}
			for (int i = 0; i < this.m_HeadInfos.TableHeadInfos.Count; i++)
			{
				TableHeadCell tableHeadCell = this.m_HeadInfos.TableHeadInfos[i];
				double num = 0.0;
				double num2 = 0.0;
				this.m_HeadInfos.CellPosition(tableHeadCell, ref num, ref num2);
				XYZ xyz = this.m_TablePosition + new XYZ(num, -num2, 0.0);
				double num3 = this.m_HeadInfos.CellWidth(tableHeadCell);
				double num4 = this.m_HeadInfos.CellHeight(tableHeadCell);
				foreach (TextElement textElement in textNoteList)
				{
					BoundingBoxXYZ boundingBoxXYZ = textElement.get_BoundingBox(view);
					XYZ xyz2 = boundingBoxXYZ.Min + (boundingBoxXYZ.Max - boundingBoxXYZ.Min) / 2.0;
					if (Geometry.LessThan(xyz.X, xyz2.X) && Geometry.LessThan(xyz2.X, xyz.X + num3) && Geometry.LessThan(xyz.Y - num4, xyz2.Y) && Geometry.LessThan(xyz2.Y, xyz.Y))
					{
						TableHeadCell tableHeadCell2 = tableHeadCell;
						tableHeadCell2.Value += textElement.Text;
					}
				}
			}
		}

		public bool GetCellRowColIndexList(TableHead head, XYZ ptCellLeftTop, XYZ ptCellRigthBottom, ref List<int> rowIndexList, ref List<int> colIndexList)
		{
			double x = ptCellLeftTop.X;
			double y = ptCellRigthBottom.Y;
			double x2 = ptCellRigthBottom.X;
			double y2 = ptCellLeftTop.Y;
			bool flag = false;
			bool flag2 = false;
			double num = this.m_TablePosition.Y;
			if (Geometry.IsEqual(y2, num))
			{
				flag = true;
			}
			for (int i = 0; i < head.GetCellHeightList().Count; i++)
			{
				num -= head.GetCellHeightList()[i];
				if (!flag && Geometry.IsEqual(y2, num))
				{
					flag = true;
				}
				else if (flag && Geometry.Lessthan_Or_Equal(y, num))
				{
					rowIndexList.Add(i);
					flag2 = true;
				}
			}
			if (!flag || !flag2)
			{
				return false;
			}
			bool flag3 = false;
			bool flag4 = false;
			double num2 = this.m_TablePosition.X;
			if (Geometry.IsEqual(x, num2))
			{
				flag3 = true;
			}
			for (int i = 0; i < head.GetCellWidthList().Count; i++)
			{
				num2 += head.GetCellWidthList()[i];
				if (!flag3 && Geometry.IsEqual(x, num2))
				{
					flag3 = true;
				}
				else if (flag3 && Geometry.Lessthan_Or_Equal(num2, x2))
				{
					colIndexList.Add(i);
					flag4 = true;
				}
			}
			return flag3 && flag4;
		}

		private ExternalCommandData m_Revit;

		private Document m_FamilyDocument;

		private List<Line> m_HorizontalLineList = new List<Line>();

		private List<Line> m_VerticalLineList = new List<Line>();

		private XYZ m_TablePosition;

		private TableHead m_HeadInfos;
	}
}
